<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Incomplete JSON Pretty Printer</title>
  <style>
    :root {
      --primary-color: #3498db;
      --secondary-color: #2980b9;
      --background-color: #f9f9f9;
      --card-background: #ffffff;
      --text-color: #333333;
      --border-color: #e0e0e0;
    }
    
    * {
      box-sizing: border-box;
      margin: 0;
      padding: 0;
    }
    
    body {
      font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
      line-height: 1.6;
      color: var(--text-color);
      background-color: var(--background-color);
      padding: 20px;
      max-width: 1000px;
      margin: 0 auto;
    }
    
    .container {
      display: flex;
      flex-direction: column;
      gap: 20px;
    }
    
    .card {
      background: var(--card-background);
      border-radius: 8px;
      box-shadow: 0 2px 10px rgba(0,0,0,0.1);
      padding: 20px;
      transition: all 0.3s ease;
    }
    
    h2 {
      color: var(--primary-color);
      margin-bottom: 10px;
      font-weight: 600;
    }
    
    h3 {
      margin-bottom: 10px;
    }
    
    p {
      margin-bottom: 15px;
      color: #666;
    }
    
    textarea {
      width: 100%;
      height: 180px;
      font-family: 'Consolas', 'Monaco', monospace;
      font-size: 14px;
      padding: 12px;
      border-radius: 6px;
      border: 1px solid var(--border-color);
      resize: vertical;
      transition: border 0.3s ease;
    }
    
    textarea:focus {
      outline: none;
      border-color: var(--primary-color);
      box-shadow: 0 0 0 2px rgba(52, 152, 219, 0.2);
    }
    
    .button-group {
      display: flex;
      gap: 10px;
      margin: 15px 0;
      flex-wrap: wrap;
    }
    
    button {
      background-color: var(--primary-color);
      color: white;
      border: none;
      padding: 10px 16px;
      font-size: 14px;
      border-radius: 6px;
      cursor: pointer;
      transition: background-color 0.3s ease;
      display: flex;
      align-items: center;
      gap: 6px;
    }
    
    button:hover {
      background-color: var(--secondary-color);
    }
    
    pre {
      background: #f0f0f0;
      padding: 15px;
      border-radius: 6px;
      border-left: 4px solid var(--primary-color);
      overflow-x: auto;
      white-space: pre-wrap;
      word-wrap: break-word;
      font-family: 'Consolas', 'Monaco', monospace;
      font-size: 14px;
      line-height: 1.5;
      min-height: 50px;
    }
    
    .output-header {
      display: flex;
      justify-content: space-between;
      align-items: center;
      margin-bottom: 10px;
    }
    
    .copy-button {
      background-color: #f0f0f0;
      color: #333;
      padding: 6px 12px;
      border-radius: 4px;
      font-size: 12px;
    }
    
    .copy-button:hover {
      background-color: #e0e0e0;
    }
    
    .copy-success {
      background-color: #27ae60;
      color: white;
    }
    
    /* Responsive adjustments */
    @media (max-width: 768px) {
      body {
        padding: 12px;
      }
      
      textarea {
        height: 150px;
      }
    }
    
    @media (max-width: 480px) {
      .button-group {
        flex-direction: column;
      }
      
      button {
        width: 100%;
        justify-content: center;
      }
    }
  </style>
</head>
<body>
  <div class="container">
    <div class="card">
      <h2>Incomplete JSON Pretty Printer</h2>
      <p>Format truncated or incomplete JSON into a readable structure - updates automatically as you type.</p>
      
      <textarea id="inputJson" placeholder="Paste incomplete JSON here..."></textarea>
      
      <div class="button-group">
        <button id="exampleButton">
          <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
            <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path>
            <polyline points="14 2 14 8 20 8"></polyline>
            <line x1="16" y1="13" x2="8" y2="13"></line>
            <line x1="16" y1="17" x2="8" y2="17"></line>
            <polyline points="10 9 9 9 8 9"></polyline>
          </svg>
          Load Pelican Example
        </button>
        <button id="clearButton">
          <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
            <rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect>
            <line x1="9" y1="9" x2="15" y2="15"></line>
            <line x1="15" y1="9" x2="9" y2="15"></line>
          </svg>
          Clear
        </button>
      </div>
    </div>

    <div class="card">
      <div class="output-header">
        <h3>Formatted JSON</h3>
        <button id="copyButton" class="copy-button">
          <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
            <rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
            <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
          </svg>
          Copy to Clipboard
        </button>
      </div>
      <pre id="outputJson"></pre>
    </div>
  </div>

  <script>
    document.addEventListener('DOMContentLoaded', function() {
      const inputJson = document.getElementById('inputJson');
      const outputJson = document.getElementById('outputJson');
      const copyButton = document.getElementById('copyButton');
      const exampleButton = document.getElementById('exampleButton');
      const clearButton = document.getElementById('clearButton');
      
      // Auto-update when input changes
      inputJson.addEventListener('input', function() {
        updateOutput();
      });
      
      // Copy to clipboard functionality
      copyButton.addEventListener('click', function() {
        const textToCopy = outputJson.textContent;
        
        navigator.clipboard.writeText(textToCopy).then(function() {
          // Success feedback
          copyButton.classList.add('copy-success');
          copyButton.textContent = '✓ Copied!';
          
          setTimeout(function() {
            copyButton.classList.remove('copy-success');
            copyButton.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg> Copy to Clipboard';
          }, 2000);
        });
      });
      
      // Load example JSON
      exampleButton.addEventListener('click', function() {
        const pelicanExample = `{"pelican":{"name":"Brown Pelican","scientificName":"Pelecanus occidentalis","features":{"wingspan":"2.3 meters","weight":"3.5 kg","colors":["brown","white","gray"]},"habitat":"coastal areas","diet":["fish","crustaceans"],"conservation`;
        
        inputJson.value = pelicanExample;
        updateOutput();
      });
      
      // Clear input
      clearButton.addEventListener('click', function() {
        inputJson.value = '';
        outputJson.textContent = '';
      });
      
      // Function to update output
      function updateOutput() {
        const input = inputJson.value.trim();
        
        if (!input) {
          outputJson.textContent = '';
          return;
        }
        
        const formatted = prettyFormat(input);
        outputJson.textContent = formatted;
      }
      
      // Function to format JSON
      function prettyFormat(jsonString) {
        let result = '';
        let indentLevel = 0;
        let inString = false;
        const indentSize = 2;
        
        for (let i = 0; i < jsonString.length; i++) {
          const char = jsonString[i];
          const prevChar = i > 0 ? jsonString[i - 1] : '';
          
          // Handle string content
          if (char === '"' && prevChar !== '\\') {
            inString = !inString;
            result += char;
            continue;
          }
          
          if (inString) {
            // Inside string, add characters as-is
            result += char;
          } else {
            // Outside string, format JSON
            switch (char) {
              case '{':
              case '[':
                result += char;
                indentLevel++;
                result += '\n' + ' '.repeat(indentLevel * indentSize);
                break;
                
              case '}':
              case ']':
                indentLevel--;
                result = result.trimEnd();
                result += '\n' + ' '.repeat(indentLevel * indentSize) + char;
                break;
                
              case ',':
                result += char;
                result += '\n' + ' '.repeat(indentLevel * indentSize);
                break;
                
              case ':':
                result += ': ';
                break;
                
              case ' ':
              case '\n':
              case '\r':
              case '\t':
                // Skip all whitespace in non-string context
                break;
                
              default:
                result += char;
                break;
            }
          }
        }
        
        return result;
      }
      
      // Initialize on page load
      updateOutput();
    });
  </script>
</body>
</html>
